home *** CD-ROM | disk | FTP | other *** search
/ Super PC 33 / Super PC 33 (Shareware).iso / spc / sonido / timidity / source / sun_audi.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-08-06  |  6.5 KB  |  255 lines

  1. /* 
  2.  
  3.     TiMidity -- Experimental MIDI to WAVE converter
  4.     Copyright (C) 1995 Tuukka Toivonen <titoivon@snakemail.hut.fi>
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     sun_audio.c
  21.  
  22.     Functions to play sound on a Sun's /dev/audio. 
  23.  
  24.     THESE ARE UNTESTED -- If you need to make modifications to get
  25.     them to work, please send me the diffs, preferrably with a brief 
  26.     explanation of what was wrong. Thanks!
  27.  
  28. */
  29.  
  30. #include <unistd.h>
  31. #include <fcntl.h>
  32. #include <errno.h>
  33.  
  34. #include <sys/ioctl.h> 
  35. #include <sun/audioio.h>
  36.  
  37. #include "config.h"
  38. #include "output.h"
  39. #include "controls.h"
  40.  
  41. static int open_output(void); /* 0=success, 1=warning, -1=fatal error */
  42. static void close_output(void);
  43. static void output_data(int32 *buf, int32 count);
  44. static void flush_output(void);
  45. static void purge_output(void);
  46.  
  47. /* export the playback mode */
  48.  
  49. #define dpm sun_play_mode
  50.  
  51. PlayMode dpm = {
  52.   DEFAULT_RATE, PE_16BIT|PE_SIGNED,
  53.   -1,
  54.   {}, /* no extra parameters so far */
  55.   "Sun audio device", 'd',
  56.   "/dev/audio",
  57.   open_output,
  58.   close_output,
  59.   output_data,
  60.   flush_output,
  61.   purge_output  
  62. };
  63.  
  64. /*************************************************************************/
  65. /*
  66.    Encoding will be 16-bit linear signed, unless PE_ULAW is set, in
  67.    which case it'll be 8-bit uLaw. I don't think it's worthwhile to
  68.    implement any 8-bit linear modes as the sound quality is
  69.    unrewarding. PE_MONO is honored.  */
  70.  
  71. static audio_info_t auinfo;
  72.  
  73. static int open_output(void)
  74. {
  75.   int fd, tmp, i, warnings=0;
  76.   
  77.   /* Open the audio device */
  78.   fd=open(dpm.name, O_RDWR | O_NDELAY);
  79.   if (fd<0)
  80.     {
  81.       ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
  82.        dpm.name, sys_errlist[errno]);
  83.       return -1;
  84.     }
  85.  
  86.  
  87.   /* Does any device need byte-swapped data? Turn the bit off here. */
  88.   dpm.encoding &= ~PE_BYTESWAP;
  89.  
  90.  
  91.   AUDIO_INITINFO(&auinfo);
  92.  
  93.   if (ioctl(fd, AUDIO_GETINFO, &auinfo)<0)
  94.     { 
  95.       /* If it doesn't give info, it probably won't take requests
  96.      either. Assume it's an old device that does 8kHz uLaw only.
  97.  
  98.      Disclaimer: I don't know squat about the various Sun audio
  99.      devices, so if this is not what we should do, I'll gladly
  100.      accept modifications. */
  101.  
  102.       ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Cannot inquire %s", dpm.name);
  103.  
  104.       dpm.encoding = PE_ULAW|PE_MONO;
  105.       dpm.rate = 8000;
  106.       warnings=1;
  107.     }
  108.   else
  109.     {
  110.       ctl->cmsg(CMSG_INFO,VERB_DEBUG, 
  111.         "1. precision=%d  channels=%d  encoding=%d  sample_rate=%d",
  112.         auinfo.play.precision, auinfo.play.channels,
  113.         auinfo.play.encoding, auinfo.play.sample_rate);
  114.       ctl->cmsg(CMSG_INFO,VERB_DEBUG, 
  115.         "1. (dpm.encoding=0x%02x  dpm.rate=%d)",
  116.         dpm.encoding, dpm.rate);
  117.  
  118.  
  119.       /* Select 16-bit linear / 8-bit uLaw encoding */
  120.  
  121.       if (dpm.encoding & PE_ULAW)
  122.     {
  123.       auinfo.play.precision = 8;
  124.       auinfo.play.encoding = AUDIO_ENCODING_ULAW;
  125.     }
  126.       else
  127.     {
  128.       auinfo.play.precision = 16;
  129.       auinfo.play.encoding = AUDIO_ENCODING_LINEAR;
  130.     }
  131.       if (ioctl(fd, AUDIO_SETINFO, &auinfo)<0)
  132.     {
  133.       /* Try the other one instead */
  134.       if (dpm.encoding & PE_ULAW)
  135.         {
  136.           auinfo.play.precision = 16;
  137.           auinfo.play.encoding = AUDIO_ENCODING_LINEAR;
  138.         }
  139.       else
  140.         {
  141.           auinfo.play.precision = 8;
  142.           auinfo.play.encoding = AUDIO_ENCODING_ULAW;
  143.         }
  144.       if (ioctl(fd, AUDIO_SETINFO, &auinfo)<0)
  145.         {
  146.           ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
  147.            "%s doesn't support 16-bit linear or 8-bit uLaw samples", 
  148.            dpm.name);
  149.           close(fd);
  150.           return -1;
  151.         }
  152.       dpm.encoding ^= PE_ULAW;
  153.       ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Encoding adjusted to %s",
  154.             (dpm.encoding & PE_ULAW) ? "uLaw" : "16-bit linear");
  155.       warnings=1;
  156.     }
  157.       /* Set the other bits right. */
  158.       if (dpm.encoding & PE_ULAW)
  159.     dpm.encoding &= ~(PE_16BIT|PE_SIGNED);
  160.       else
  161.     dpm.encoding |= PE_16BIT|PE_SIGNED;
  162.  
  163.  
  164.       /* Select stereo or mono samples */
  165.  
  166.       auinfo.play.channels = (dpm.encoding & PE_MONO) ? 1 : 2;
  167.       if (ioctl(fd, AUDIO_SETINFO,&auinfo)<0)
  168.     {
  169.       auinfo.play.channels = (dpm.encoding & PE_MONO) ? 2 : 1;
  170.       if ((dpm.encoding & PE_MONO) ||
  171.           (ioctl(fd, AUDIO_SETINFO,&auinfo)<0))
  172.         {
  173.           ctl->cmsg(CMSG_ERROR, VERB_NORMAL, 
  174.            "%s doesn't support mono or stereo samples", dpm.name);
  175.           close(fd);
  176.           return -1;
  177.         }
  178.       dpm.encoding ^= PE_MONO;
  179.       ctl->cmsg(CMSG_WARNING, VERB_VERBOSE, "Sound adjusted to %sphonic", 
  180.             (dpm.encoding & PE_MONO) ? "mono" : "stereo");
  181.       warnings=1;
  182.     }
  183.  
  184.  
  185.       /* Select sampling rate */
  186.  
  187.       auinfo.play.sample_rate=dpm.rate;
  188.       if (ioctl(fd, AUDIO_SETINFO,&auinfo)<0)
  189.     {
  190.       ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
  191.             "%s doesn't support a %d Hz sample rate",
  192.             dpm.name, dpm.rate);
  193.       close(fd);
  194.       return -1;
  195.     }
  196.       /* This may be pointless -- do the Sun devices give an error if
  197.          the sampling rate can't be produced exactly? */
  198.       if (auinfo.play.sample_rate != dpm.rate)
  199.     {
  200.       dpm.rate=auinfo.play.sample_rate;
  201.       ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
  202.             "Output rate adjusted to %d Hz", dpm.rate);
  203.       warnings=1;
  204.     }
  205.  
  206.  
  207.       ctl->cmsg(CMSG_INFO,VERB_DEBUG, 
  208.         "2. precision=%d  channels=%d  encoding=%d  sample_rate=%d",
  209.         auinfo.play.precision, auinfo.play.channels,
  210.         auinfo.play.encoding, auinfo.play.sample_rate);
  211.       ctl->cmsg(CMSG_INFO,VERB_DEBUG, 
  212.         "2. (dpm.encoding=0x%02x  dpm.rate=%d)",
  213.         dpm.encoding, dpm.rate);
  214.     }
  215.  
  216.   dpm.fd=fd;
  217.   
  218.   return warnings;
  219. }
  220.  
  221. static void output_data(int32 *buf, int32 count)
  222. {
  223.   if (!(dpm.encoding & PE_MONO)) count*=2; /* Stereo samples */
  224.   
  225.   if (dpm.encoding & PE_ULAW)
  226.     {
  227.       /* Convert to 8-bit uLaw and write out. */
  228.       s32toulaw(buf, NULL, count);
  229.       
  230.       while ((-1==write(dpm.fd, buf, count)) && errno==EINTR)
  231.     ;
  232.     }
  233.   else
  234.     {
  235.       /* Convert data to signed 16-bit PCM */
  236.       s32tos16(buf, NULL, count);
  237.       
  238.       while ((-1==write(dpm.fd, buf, count * 2)) && errno==EINTR)
  239.     ;
  240.     }
  241. }
  242.  
  243. static void close_output(void)
  244. {
  245.   close(dpm.fd);
  246. }
  247.  
  248. static void flush_output(void)
  249. {
  250. }
  251.  
  252. static void purge_output(void)
  253. {
  254. }
  255.